package cn.maihe.elg.operation.supports.electronicseal.kt.cloudsign;

import cn.maihe.elg.operation.model.bo.GuaranteeTemplatePdfParams;
import cn.maihe.elg.operation.model.bo.ReceiveTemplatePdfParams;
import cn.maihe.elg.operation.model.enums.AttachmentFileType;
import cn.maihe.elg.operation.model.enums.CenterNoEnum;
import cn.maihe.elg.operation.model.enums.GuaranteeTemplateType;
import cn.maihe.elg.operation.repository.entity.AcceptOrderInfoDO;
import cn.maihe.elg.operation.repository.entity.KtCustomerDO;
import cn.maihe.elg.operation.service.business.KtCustomerService;
import cn.maihe.elg.operation.service.order.AcceptOrderInfoService;
import cn.maihe.elg.operation.service.order.GuaranteeAttachmentInfoService;
import cn.maihe.elg.operation.supports.electronicseal.kt.KtConfig;
import cn.maihe.elg.operation.supports.electronicseal.kt.cloudsign.dto.VerifySealRespDTO;
import cn.maihe.elg.operation.supports.electronicseal.kt.cloudsign.util.KtOfdCloudConvertUtil;
import cn.maihe.elg.operation.supports.electronicseal.kt.cloudsign.util.KtOfdCloudSignatureUtil;
import cn.maihe.elg.operation.supports.system.ElgResourceService;
import cn.maihe.elg.operation.utils.CreateGuaranteeUtil;
import cn.maihe.elg.operation.utils.DocFillUtil;
import cn.maihe.elg.operation.utils.ValidateUtil;
import com.alibaba.fastjson.JSON;
import com.kinsec.KTConvert;
import com.kinsec.KTSignature;
import com.kinsec.SignatureInfo;
import com.kinsec.dom.Attachment;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.multipdf.PDFMergerUtility;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @Description 凯特ofd云签服务
 * @Author WJH
 * @Date 2022/10/12
 */
@Component
@Slf4j
public class KTOfdCloudSignService {

    private KtConfig.CloudSign cloudSign;
    private ElgResourceService elgResourceService;
    private KtOfdCloudConvertUtil ofdCloudConvertUtil;
    private KtOfdCloudSignatureUtil ofdCloudSignatureUtil;

    @Resource
    private KtCustomerService ktCustomerService;
    @Resource
    private AcceptOrderInfoService acceptOrderInfoService;
    @Resource
    private GuaranteeAttachmentInfoService guaranteeAttachmentInfoService;

    public KTOfdCloudSignService(KtConfig ktConfig, ElgResourceService elgResourceService) {
        this.cloudSign = ktConfig.getCloudSign();
        Assert.notNull(cloudSign, () -> "凯特云签服务cn.maihe.elg.kt.cloud-sign未配置");
        ofdCloudSignatureUtil = new KtOfdCloudSignatureUtil(new KTSignature(cloudSign.getOfdServer()));
        ofdCloudConvertUtil = new KtOfdCloudConvertUtil(new KTConvert(cloudSign.getOfdServer()));
        this.elgResourceService = elgResourceService;
    }

    /**
     * 电子保函签章
     * 返回 电签后的ofd文件
     */
    public Path guaranteeOfdWithAttachesSeal(String acceptOrderNo, String centerOrderId, GuaranteeTemplatePdfParams params, GuaranteeTemplatePdfParams pdfParamsForCiphertext, ArrayList<Attachment> attachments, Long orgId, Map<String, String> metas, CenterNoEnum centerNoEnum) {
        Assert.hasText(acceptOrderNo, "受理订单号不能为空");
        Assert.notNull(orgId, "机构id不能为空");
        ValidateUtil.validate(params);

        // 未签章pdf文件存储路径
        Path targetPdfPath = getTargetPdfPath(acceptOrderNo, params, pdfParamsForCiphertext,"ofd","unSeal担保保函","pdf");

        //pdf转ofd文件路径：未签章
        Path unSealTargetOfdPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "unSeal担保保函", "ofd");
        if(CreateGuaranteeUtil.isXiaMen(centerNoEnum)){
            //取投标人的注册地址赋值给电子保函文件中的投保人地址
            this.ofdCloudConvertUtil.office2OfdWithMetas(targetPdfPath, centerOrderId, unSealTargetOfdPath, metas);
        }else {
            this.ofdCloudConvertUtil.office2Ofd(targetPdfPath, unSealTargetOfdPath);
        }

        // 签章属性
        ArrayList<SignatureInfo> signatureInfos = getSignatureInfos(params, pdfParamsForCiphertext, orgId,centerNoEnum);
        log.info("guaranteeOfdWithAttachesSeal signatureInfos:{}", JSON.toJSONString(signatureInfos));

        String appId = cloudSign.getAppId();
        String secret = cloudSign.getKey();
        //签章后的ofd文件
        Path targetSealOfdPath;
        if (attachments == null) {
            targetSealOfdPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "担保保函", "ofd");
            this.ofdCloudSignatureUtil.ofdStamps(unSealTargetOfdPath, targetSealOfdPath, centerOrderId, appId, secret, signatureInfos);
            this.deleteTmpFile(unSealTargetOfdPath);
            return targetSealOfdPath;
        } else {
            log.info("attachments attachments.size:{}", attachments.size());
            //添加附件的转换，源文件必须为pdf或ofd
            Path unSealTargetOfdPathWithAttach = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "unSeal担保保函附件", "ofd");
            this.ofdCloudConvertUtil.addAttachments(unSealTargetOfdPath, unSealTargetOfdPathWithAttach, attachments);
            targetSealOfdPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, params.getGuaranteeNo(), "ofd");
            this.ofdCloudSignatureUtil.ofdStamps(unSealTargetOfdPathWithAttach, targetSealOfdPath, centerOrderId, appId, secret, signatureInfos);
            this.deleteTmpFile(unSealTargetOfdPath, unSealTargetOfdPathWithAttach);
            return targetSealOfdPath;
        }

    }

    private void deleteTmpFile(Path... tmpPath) {
        if (tmpPath != null && tmpPath.length != 0) {
            Arrays.stream(tmpPath).forEach(tmp -> {
                try {
                    Files.deleteIfExists(tmp);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    /**
     * 电子保函签章
     * 返回 电签后的pdf文件
     */
    public Path guaranteePdfSeal(String acceptOrderNo, GuaranteeTemplatePdfParams params,GuaranteeTemplatePdfParams pdfParamsForCiphertext, CenterNoEnum centerNoEnum) {
        Assert.hasText(acceptOrderNo, "受理订单号不能为空");
        ValidateUtil.validate(params);
        AcceptOrderInfoDO curDO = acceptOrderInfoService.getByAcceptOrderNo(acceptOrderNo);
        Long orgId = curDO.getOrgId();

        // 未签章pdf文件存储路径
        Path targetPdfPath = getTargetPdfPath(acceptOrderNo, params, pdfParamsForCiphertext,"ofd","guaranteePdfUnSeal","pdf");

        // 签章后的pdf文件
        Path targetSealPdfPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "guaranteePdfSeal", "pdf");

        // 签章属性
        ArrayList<SignatureInfo> signatureInfos = getSignatureInfos(params, pdfParamsForCiphertext, orgId, centerNoEnum);
        log.info("guaranteePdfSeal signatureInfos:{}", JSON.toJSONString(signatureInfos));

        String appId = cloudSign.getAppId();
        String secret = cloudSign.getKey();
        this.ofdCloudSignatureUtil.pdfStamps(acceptOrderNo, targetPdfPath, targetSealPdfPath, appId, secret, signatureInfos);
        String remark = String.format("%s", targetSealPdfPath.getFileName());
        guaranteeAttachmentInfoService.saveOrUpdateAttachmentInfo(curDO, targetSealPdfPath, AttachmentFileType.TYPE_7, remark);
        this.deleteTmpFile(targetPdfPath);
        return targetSealPdfPath;
    }

    private Path getTargetPdfPath(String acceptOrderNo, GuaranteeTemplatePdfParams params, GuaranteeTemplatePdfParams pdfParamsForCiphertext,String subPath, String fileName, String fileType) {
        //未签章pdf文件存储路径
        Path targetPdfPath = elgResourceService.buildSaveAbsolutePath(subPath, acceptOrderNo, fileName, fileType);

        if(Objects.nonNull(pdfParamsForCiphertext)){
            //担保保函模板填充后docx文件
            Path sourceDocxPathPlaintext = elgResourceService.buildGuaranteeFileByTemplate(acceptOrderNo, params,"担保保函_明文");
            //未签章pdf文件存储路径
            Path targetPdfPathPlaintext = elgResourceService.buildSaveAbsolutePath(subPath, acceptOrderNo, "guaranteePdfUnSealForPlaintext", fileType);
            DocFillUtil.doc2pdf(sourceDocxPathPlaintext, targetPdfPathPlaintext, null);


            //担保保函模板填充后docx文件
            Path sourceDocxPathForCiphertext = elgResourceService.buildGuaranteeFileByTemplate(acceptOrderNo, pdfParamsForCiphertext,"担保保函_密文");
            //未签章pdf文件存储路径
            Path targetPdfPathForCiphertext = elgResourceService.buildSaveAbsolutePath(subPath, acceptOrderNo, "guaranteePdfUnSealForCiphertext)", fileType);
            //docx转pdf
            DocFillUtil.doc2pdf(sourceDocxPathForCiphertext, targetPdfPathForCiphertext, null);

            try {
                PDFMergerUtility merger = new PDFMergerUtility();
                // 输出文件路径
                merger.setDestinationFileName(targetPdfPath.toAbsolutePath().toString());
                // 输入文件1 密文
                merger.addSource(targetPdfPathForCiphertext.toAbsolutePath().toString());
                // 输入文件2 明文
                merger.addSource(targetPdfPathPlaintext.toAbsolutePath().toString());
                // 执行合并
                merger.mergeDocuments(null);
            } catch (IOException e) {
                this.deleteTmpFile(sourceDocxPathPlaintext,targetPdfPathPlaintext,sourceDocxPathForCiphertext,targetPdfPathForCiphertext);
                throw new RuntimeException("合成pdf失败",e);
            }
            this.deleteTmpFile(sourceDocxPathPlaintext,targetPdfPathPlaintext,sourceDocxPathForCiphertext,targetPdfPathForCiphertext);
        } else {
            //担保保函模板填充后docx文件
            Path sourceDocxPath = elgResourceService.buildGuaranteeFileByTemplate(acceptOrderNo, params);
            //docx转pdf
            DocFillUtil.doc2pdf(sourceDocxPath, targetPdfPath, null);
            this.deleteTmpFile(sourceDocxPath);
        }
        return targetPdfPath;
    }

    private ArrayList<SignatureInfo> getSignatureInfos(GuaranteeTemplatePdfParams params, GuaranteeTemplatePdfParams pdfParamsForCiphertext, Long orgId, CenterNoEnum centerNoEnum) {
        GuaranteeTemplateType type = params.getGuaranteeTemplateType();

        //电子保函ofd联合签章 ::page x y 值是根据现有模板内置的
        //68f, 197f  115f, 213f
        //120F,200F,80F,220F

        KtCustomerDO orgKtCustomerDO = ktCustomerService.selectByOrgId(orgId, "1");
        KtCustomerDO legalKtCustomerDO = ktCustomerService.selectByOrgId(orgId, "2");
        String ztCompanyToken = orgKtCustomerDO.getToken();
        String ztLegalToken = legalKtCustomerDO.getToken();

        ArrayList<SignatureInfo> signatureInfos;
        if(Objects.nonNull(pdfParamsForCiphertext)){
            signatureInfos = KtOfdCloudSignatureUtil.MySignatureInfo.init()
                    .add(ztCompanyToken, type.getSignPageNum()-1, type.getSignOrgXpx(), type.getSignOrgYpx())
                    .add(ztCompanyToken, type.getSignPageNum()*2-1, type.getSignOrgXpx(), type.getSignOrgYpx()).toSignatureInfos();
        } else {
            if(CreateGuaranteeUtil.isMeiShan(centerNoEnum)){
                signatureInfos = KtOfdCloudSignatureUtil.MySignatureInfo.init()
                        .add(ztCompanyToken, type.getSignPageNum()-1, type.getSignOrgXpx(), type.getSignOrgYpx()).toSignatureInfos();
            }else {
                signatureInfos = KtOfdCloudSignatureUtil.MySignatureInfo.init()
                        .add(ztCompanyToken, type.getSignPageNum(), type.getSignOrgXpx(), type.getSignOrgYpx())
                        .add(ztLegalToken, type.getSignPageNum(), type.getSignLegalXpx(), type.getSignLegalYpx()).toSignatureInfos();
            }
        }
        return signatureInfos;
    }

    /**
     * 到账证明签章
     * 返回 电签后的ofd文件
     */
    public Path receiveOfdSeal(String ztCompanyToken, String acceptOrderNo, ReceiveTemplatePdfParams params) {
        Assert.hasText(acceptOrderNo, "受理订单号不能为空");
        ValidateUtil.validate(params);

        //模板填充docx
        Path targetDocPath = elgResourceService.buildReceiveFileByTemplate(acceptOrderNo, params);
        //docx转ofd
        Path targetOfdPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "unSeal到账证明", "ofd");
        ofdCloudConvertUtil.office2Ofd(targetDocPath, targetOfdPath);
        //电子保函ofd联合签章 ::page x y 值是根据现有模板内置的
        ArrayList<SignatureInfo> signatureInfos = KtOfdCloudSignatureUtil.MySignatureInfo.init()
                .add(ztCompanyToken, 0, 130f, 180f).toSignatureInfos();
        //签章后的ofd文件
        Path targetSealOfdPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "到账证明", "ofd");

        try {
            return ofdCloudSignatureUtil.ofdStamps(targetOfdPath, targetSealOfdPath, cloudSign.getAppId(), cloudSign.getKey(), signatureInfos);
        } catch (Exception e) {
            throw new RuntimeException("到账证明签章失败:" + e.getMessage(), e);
        }
    }

    /**
     * 到账证明签章
     * 返回 电签后的pdf文件
     */
    public Path receivePdfSeal(String acceptOrderNo, ReceiveTemplatePdfParams params) {
        Assert.hasText(acceptOrderNo, "受理订单号不能为空");
        ValidateUtil.validate(params);
        AcceptOrderInfoDO curDO = acceptOrderInfoService.getByAcceptOrderNo(acceptOrderNo);
        Long orgId = curDO.getOrgId();
        KtCustomerDO orgKtCustomerDO = ktCustomerService.selectByOrgId(orgId, "1");
        String ztCompanyToken = orgKtCustomerDO.getToken();

        //模板填充docx
        Path targetDocPath = elgResourceService.buildReceiveFileByTemplate(acceptOrderNo, params);
        //docx转pdf
        Path targetPdfPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "receivePdfUnSeal", "pdf");
        targetPdfPath = DocFillUtil.doc2pdf(targetDocPath, targetPdfPath, null);
        //        ofdCloudConvertUtil.office2Ofd(targetDocPath, targetOfdPath);
        //电子保函pdf联合签章 ::page x y 值是根据现有模板内置的
        ArrayList<SignatureInfo> signatureInfos = KtOfdCloudSignatureUtil.MySignatureInfo.init()
                .add(ztCompanyToken, 0, 130f, 180f).toSignatureInfos();
        //签章后的pdf文件
        Path targetSealPdfPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "receivePdfSeal", "pdf");

        try {
            this.ofdCloudSignatureUtil.pdfStamps(acceptOrderNo, targetPdfPath, targetSealPdfPath, cloudSign.getAppId(), cloudSign.getKey(), signatureInfos);
            String remark = String.format("%s", targetSealPdfPath.getFileName());
            guaranteeAttachmentInfoService.saveOrUpdateAttachmentInfo(curDO, targetSealPdfPath, AttachmentFileType.TYPE_6, remark);
            this.deleteTmpFile(targetDocPath, targetPdfPath);
            return targetSealPdfPath;
        } catch (Exception e) {
            throw new RuntimeException("到账证明签章失败:" + e.getMessage(), e);
        }


    }

    /**
     * ofd验签方法
     * @param acceptOrderNo 系统保函申请订单编号
     * @param sourceOfdPath 验签文件
     * @return
     */
    public List<VerifySealRespDTO> ofdVerifySeal(String acceptOrderNo, Path sourceOfdPath) {
        return this.ofdCloudSignatureUtil.ofdVerifySeal(acceptOrderNo,sourceOfdPath);
    }
}
